import { Context } from 'koa';
import axios from 'axios';

/**
 * 从请求中获取真实IP地址
 */
export function getClientIp(ctx: Context): string {
  const forwarded = ctx.request.headers['x-forwarded-for'];
  const realIp = ctx.request.headers['x-real-ip'];

  if (forwarded) {
    const ips = String(forwarded).split(',');
    return ips[0]?.trim() || 'unknown';
  }
  if (realIp) {
    return String(realIp);
  }
  return ctx.request.ip || 'unknown';
}

/**
 * 获取IP归属地信息（使用免费接口）
 */
export async function getIpLocation(ip: string): Promise<string> {
  if (
    !ip ||
    ip === 'unknown' ||
    ip === '127.0.0.1' ||
    ip === '::1' ||
    ip.startsWith('192.168.')
  ) {
    return '本地';
  }

  try {
    const res = await axios.get(`https://ipapi.co/${ip}/json/`, { timeout: 3000 });
    const data = res.data || {};
    if (data.country_name && (data.city || data.region)) {
      return `${data.country_name} ${data.region || ''} ${data.city || ''}`.trim();
    }
    return data.country_name || '未知';
  } catch {
    try {
      const res = await axios.get(`http://ip-api.com/json/${ip}?lang=zh-CN`, { timeout: 2000 });
      const data = res.data || {};
      if (data.status === 'success') {
        return `${data.country || ''} ${data.regionName || ''} ${data.city || ''}`.trim();
      }
    } catch {}
    return '未知';
  }
}

/**
 * 返回：{ browser, os, device }
 */
export function parseUserAgent(userAgent: string) {
  const ua = (userAgent || '').trim();

  const { name: browserName, version: browserVersion } = detectBrowser(ua);
  const { name: osName, version: osVersion } = detectOS(ua);
  const device = detectDevice(ua);

  return {
    browser: browserName ? (browserVersion ? `${browserName} ${browserVersion}` : browserName) : '未知',
    os: osName ? (osVersion ? `${osName} ${osVersion}` : osName) : '未知',
    device: device || 'desktop',
  };
}

function detectBrowser(ua: string): { name: string; version: string } {
  const rules: Array<[name: string, re: RegExp, vIdx?: number]> = [
    ['Edge', /Edg\/([\d.]+)/, 1],
    ['Opera', /OPR\/([\d.]+)/, 1],
    ['Firefox', /Firefox\/([\d.]+)/, 1],
    ['Chrome', /Chrome\/([\d.]+)/, 1],
    ['Safari', /Version\/([\d.]+).*Safari/, 1],
    // IE (老版本)
    ['IE', /MSIE\s([\d.]+)/, 1],
    // IE 11+
    ['IE', /Trident\/.*rv:([\d.]+)/, 1],
  ];

  for (const [name, re, idx = 1] of rules) {
    const m = ua.match(re);
    if (m) return { name, version: m[idx] || '' };
  }
  return { name: '', version: '' };
}

function detectOS(ua: string): { name: string; version: string } {
  // iOS
  let m = ua.match(/\((iPhone|iPad|iPod).*?OS\s([\d_]+)/i);
  if (m) return { name: 'iOS', version: (m[2] || '').replace(/_/g, '.') };

  // Android
  m = ua.match(/Android\s([\d.]+)/i);
  if (m) return { name: 'Android', version: m[1] || '' };

  // macOS
  m = ua.match(/Mac OS X\s([\d_]+)/i);
  if (m) return { name: 'macOS', version: (m[1] || '').replace(/_/g, '.') };

  // Windows
  m = ua.match(/Windows NT\s([\d.]+)/i);
  if (m) {
    const map: Record<string, string> = {
      '10.0': '10',
      '6.3': '8.1',
      '6.2': '8',
      '6.1': '7',
      '6.0': 'Vista',
      '5.1': 'XP',
    };
    const raw = m[1] || '';
    return { name: 'Windows', version: map[raw] || raw };
  }

  // Linux
  if (/Linux/i.test(ua)) return { name: 'Linux', version: '' };

  return { name: '', version: '' };
}

function detectDevice(ua: string): 'mobile' | 'tablet' | 'desktop' {
  const isIpad = /iPad/i.test(ua);
  const isTablet = /Tablet/i.test(ua) || (/(Android)(?!.*Mobile)/i.test(ua));
  const isMobile = /Mobile|iPhone|iPod|Android.*Mobile/i.test(ua);

  if (isIpad || isTablet) return 'tablet';
  if (isMobile) return 'mobile';
  return 'desktop';
}

/**
 * 获取完整的客户端信息
 */
export async function getClientInfo(ctx: Context) {
  const ip = getClientIp(ctx);
  const userAgent = String(ctx.request.headers['user-agent'] || '');
  const { browser, os, device } = parseUserAgent(userAgent);

  let ipLocation = '未知';
  try {
    ipLocation = await getIpLocation(ip);
  } catch {}

  return {
    ip,
    ipLocation,
    userAgent,
    browser,
    os,
    device,
  };
}
